﻿using System;
using System.Net;
using System.Web;

namespace SAP.BusinessOne.Web.Proxy
{
    public static class HttpBot
    {
        public static void QuickForward(HttpRequest request, HttpResponse response, string host, string identity)
        {
            var req = CreateRequest(request, host, identity);
            try
            {
                var res = req.GetResponse() as HttpWebResponse;

                // rewrite Location for 301 and 302
                RewriteLocation(request, response, res, host);

                RewriteResponse(response, res);
            }
            catch (WebException e)
            {
                var res = e.Response as HttpWebResponse;
                if (res == null)
                {
                    throw;
                }
                RewriteResponse(response, res);
            }
        }

        private static void RewriteLocation(HttpRequest request, HttpResponse response, HttpWebResponse res, string host)
        {
            const string LOCATION = "Location";

            if (res.StatusCode == HttpStatusCode.Moved || res.StatusCode == HttpStatusCode.Found)
            {
                var location = res.Headers[LOCATION];
                if(!string.IsNullOrEmpty(location))
                {
                    res.Headers.Remove(LOCATION);
                    location = location.Replace(host, request.Url.GetHost());
                    response.Headers.Add(LOCATION, location);
                }
            }
        }

        private static void RewriteResponse(HttpResponse response, HttpWebResponse res)
        {
            // never display default IIS errors
            response.TrySkipIisCustomErrors = true;

            // status
            response.StatusCode = (int)res.StatusCode;

            // header
            response.Headers.Add(res.Headers);

            // body
            response.BinaryWrite(res.GetResponseStream().ToBinary());
        }

        private static HttpWebRequest CreateRequest(HttpRequest request, string host, string identity)
        {
            var req = WebRequest.CreateHttp(host + request.RawUrl);

            // restricted headers
            ProceedRestrictedHeaders(request, req);

            // common header
            ProceedCommonHeaders(request, req);

            // identity
            req.Headers.Add("X-IDENTITY", identity);

            // body
            var body = request.GetBufferedInputStream().ToBinary();
            if (body.Length > 0)
            {
                req.GetRequestStream().Write(body, 0, body.Length);
            }

            return req;
        }

        private static void ProceedCommonHeaders(HttpRequest request, HttpWebRequest req)
        {
            foreach (string key in request.Headers.Keys)
            {
                if (!WebHeaderCollection.IsRestricted(key))
                {
                    req.Headers.Add(key, request.Headers[key]);
                }
            }
        }

        private static void ProceedRestrictedHeaders(HttpRequest request, HttpWebRequest req)
        {
            req.AllowAutoRedirect = false;

            // Method
            req.Method = request.HttpMethod;

            // Accept
            if (request.AcceptTypes != null) req.Accept = string.Join(",", request.AcceptTypes);

            // Connection

            // Content-Length
            req.ContentLength = request.ContentLength;

            // Content-Type
            req.ContentType = request.ContentType;

            // Date            
            // Expect            
            // Host
            // If-Modified-Since            
            // Range

            // Referer
            if (request.UrlReferrer != null) req.Referer = request.UrlReferrer.ToString();

            // Transfer-Encoding

            // User-Agent
            req.UserAgent = request.UserAgent;

            // Proxy-Connection
        }
    }
}